package net.scala.chapter4.test

import java.util
import java.util.{Collection => JCollection}

import com.typesafe.scalalogging.slf4j.LazyLogging
import net.scala.chapter4.c.{Just, Maybe, Nil => Null}
import org.scalatest._

import scala.collection.parallel.ForkJoinTaskSupport
import scala.collection.parallel.immutable.ParVector
import scala.io.Source
import scala.xml.XML

/**
 * @author Barudisshu
 */
class TestScala extends FunSuite with BeforeAndAfter with Matchers {

  info("Starting... ")

  /*------------
   |变量部分
   ------------*/

  private var xs: List[Int] = _
  private var ys: List[Int] = _
  private var hs: List[Int] = _
  private var oddNumber: List[Int] = _
  private var evenNumbers: List[Int] = _
  private var cs: List[Char] = _
  private var ss: List[String] = _

  before {

    xs = List(1, 2, 3)
    ys = List(20, 30, 40)
    hs = List(100, 200, 300)
    oddNumber = List(1, 3, 5, 7)
    evenNumbers = List(2, 4, 6, 8)
    cs = List('a', 'b', 'c')
    ss = List("one", "two", "three")
  }


  /*------------
   |测试部分
   ------------*/

  test("类型参数化测试"){

    /**
     * 参数化的方法
     */
    def position[A](xs:List[A],value:A):Maybe[Int] = {
      val index = xs.indexOf(value)
      if(index != -1) Just(index) else Null
    }

    println(s"\'two\'在列表${ss}对应的下标是：${position(ss, "two").get}")
    println(f"\'40\'在列表${ys}对应的下标是：${position(ys, 40).get}")
    println(s"\'two\'在列表${List()}对应的下标是：${position(List(), "two").getOrElse(-1)}")
    println(s"\'two\'在列表${xs}对应的下标是：${position(xs, "two").getOrElse(-1)}")
  }

  test("高阶函数测试"){

    // 匿名函数作为参数进行传递
    println(xs map ((x: Int) => x + 1))
    // 匿名函数只有一个参数时，略去参数外围
    println(xs map (x => x + 1))
    // pointfree-style写法，占位符代替
    println(xs map (_ + 1))
    // 只传递函数名称，函数已经实现包装
    def addOne(x: Int) = x + 1
    println(xs map addOne)

    //---------------------------------------
    // 实现自定义的高级函数
    //---------------------------------------

    /**
     * 递归实现的高阶函数
     * @param xs List
     * @param f 函数
     */
    def map1[A, B](xs: List[A], f: A => B): List[B] = {
      xs match {
        case List() => Nil
        case head :: tail => f(head) :: map1(tail, f)
      }
    }

    println(map1(xs, addOne))

    // 另外一种实现方法，即通过for-comprehension表达式实现
    /**
     * 非递归实现的高阶函数
     * @param xs List
     * @param f 函数
     */
    def map2[A, B](f: A => B, xs: List[A]): List[B] = for (x <- xs) yield f(x)
    println(map2((x: Int) => x + 1, xs))


    //---------------------------------------
    // flatMap方法
    //---------------------------------------

    // flatMap实现集合的扁平化(flatten)：
    // 串行(sequential)或并行(pallel)集合都将获得一个新的单集合(single collection)
    println(ss flatMap (_.toList))  // List(o, n, e, t, w, o, t, h, r, e, e)
    println(ss map (_.toList))      // List(List(o, n, e), List(t, w, o), List(t, h, r, e, e), List())

    // 平面化List，list上下文转换为单List集合
    def flatten[B](xss:List[List[B]]):List[B] = {
      xss match{
        case List() => Nil
        case head :: tail => head ::: flatten(tail) // ::: 用于向尾部追加上下文内容
      }
    }

    // List扁平化实现，柯里化(currying)实现
    def flatMap1[A,B](xs:List[A])(f: A => List[B]):List[B] = {
      flatten(map1(xs,f))
    }

    println(flatMap1(ss){_.toList})
  }

  /**
   * Lambda匿名表达式和词法闭包
   * 两者除了概念不同，但是两者是处于交集关系
   */
  test("Lambda匿名表达式和词法闭包"){

    // Lambda(λ演算)的匿名函数操作
    println(hs map {_ * 10 / 100})

    // 闭包都是词法关闭的，由外部变量引起操作
    var percentage = 10
    val applyPercentage = (amount:Int) => amount * percentage / 100
    percentage = 20
    // 闭包都是惰性求值的
    println(hs map applyPercentage)
  }

  /**
   * 尾递归(tail recursion)实现
   * Scala的尾递归将转换为通常的loop循环
   */
  test("尾递归实现高阶函数"){

    /**
     * 尾递归重构扁平化操作
     */
    def flatten[B](xss:List[List[B]]):List[B] = {
      def _flatten(oldList: List[List[B]], newList: List[B]): List[B] =
        oldList match {
          case List() => newList
          case head :: tail => _flatten(tail, newList ::: head)
        }
      _flatten(xss, Nil)
    }

    println(flatten(List(cs,xs,List())))
  }

  /**
   * 折叠(fold)：接收两个参数，返回一个值，在Scala中foldRight === foldLeft.reverse
   * 二元运算避免代码重复
   * foldLeft(z)(op): 为连续的元素提供方法，从左到右，开始于z
   * foldLeft(z)(op): 与foldLeft操作相同，方向相反
   */
  test("foldLeft、foldRight refactoring") {

    def mapR[A,B](xs:List[A])(f:A => B):List[B] = {
      val startValue = List.empty[B]
      xs.foldRight(startValue){f(_) :: _}
    }

    def mapL[A,B](xs:List[A])(f:A => B):List[B] = {
      val startValue = List.empty[B]
      xs.foldLeft(startValue){(a,x) =>f(x)::a}.reverse
    }

    println(mapR(xs)(_ + 1))
    println(mapL(xs)(_ + 1))
    assertResult(true,"两者等价"){mapR(xs)(_ + 1) == mapL(xs)(_ + 1)}

    /*
     * 在Scala中，定义了折叠对应的别名系统
     * /: 表示foldLeft
     * :\ 表示foldRight
     *
     * 在foldLeft源码中，返回的是acc，其中acc初始化为z
     * acc = op(acc,head)
     * head = tail
     */
    println(xs./:(0){_ + _})    // 迭代相加，实际上为f: (a,b) => a + b的迭代，如List(1,2,3)
                                // List(1,2,3)=> z + f(0,1)
                                // 1,List(2,3)=> z + 1 + f(0,2)
                                // 1,2,List(3)=> z + 1 + 2 + f(0,3)
                                // 1,2,3=> z + 1 + 2 + 3
    println(xs./:(5){_ + _})    // 1,2,3=> z + 1 + 2 + 3=>5 + 1 + 2 + 3=>11
    println(xs.foldLeft(0) { (a, b) => a + 1})  // 返回数组长度，实际上为f: (0,b) => 0 + 1的迭代，如对List(1,2,3)
                                                // List(1,2,3)=> z + f(0,1)
                                                // 1,List(2,3)=> z + 1 + f(0,2)
                                                // 1,2,List(3)=> z + 1 + 1 + f(0,3)
                                                // 1,2,3=> z + 1 + 1 + 1
    // 因此下面是等价的
    assertResult(true,"两者等价"){xs.foldLeft(0){(a,b)=>a+1}===xs.foldRight(0){(a,b)=>b+1}}

    def exists[A](xs: List[A])(e: A) = xs.foldLeft(false) { (a, x) => a || x == e}
    assertResult(true){exists(xs)(3)}
  }

  /**
   * 函数对象测试
   */
  test("function objects"){

    // 定义一个函数对象
    object fold1{
      def apply[A,B](xs:Traversable[A],defaultValue:B)(op:(B,A)=>B) = (defaultValue /: xs)(op)
    }

    println(fold1(List(1,2,3),0){_ + _})
    println(fold1(IndexedSeq(1,2,3),0){_ + _})
    println(fold1(Set(1,2,3),0){_ + _})

    /*
     * 在Scala中定义了一系列Functionn(1,2,3,...n)函数，其中n表示接收的参数
     */

    // 定义一个只接收一个参数的函数对象
    // Scala 类型系统中定义了 type Function[-A, +B] = Function1[A, B]
    object ++ extends Function[Int,Int]{
      def apply(p:Int):Int = p + 1
    }
    // 它等价于
//    val ++ = (x:Int) => x + 1
    // 也可以用Function1的简写符号(Int => Int)表示
//    object ++ extends (Int => Int) {
//      def apply(p: Int): Int = p + 1
//    }

    println(List(10,20,30) map ++)

    // 函数组合
    val addOne: Int => Int = x => x + 1
    val addTwo: Int => Int = x => x + 2

    val addThree = addOne compose addTwo      // compose为Function1中定义的方法，f compose g 等价于 f(g(x))
    // 上述的等效实现为
    val addThree1:Int => Int = x => addOne(addTwo(x))
    assertResult(true){addThree(1) === addThree1(1)}
  }

  /**
   * 在Scala中，collection根包定义接口，子包分别对应于collection.mutable和collection.immutable
   */
  test("Scala collection hierarchy"){

    // collection.Map可以接收可变与不可变对象
    // 默认地，Scala自动导入collection.immutable.Map集合，它在Predef中被定义
    val mapping:collection.Map[String,String] = Map("Ron"->"admin","Sam"->"Analayst")
    // 若要为可变的，需要显示声明
    val mapping2:collection.Map[String,String] = collection.mutable.Map("Ron"->"admin","Sam"->"Analayst")

    assertResult(true){mapping === mapping2}

    // 高阶函数接收的都是一般函数
    // 所有函数都是值返回，f: (?=>?) = f(x)
    lazy val f: Int => Int = x => x + 1
    lazy val g: Int => List[Int] = v => List(v - 1, v, v + 1)
    lazy val h: (Int, Int) => Int = (x, y) => x + y
    lazy val p: (Int) => Boolean = x => x > 2
//    def p(x:Int):Boolean = x > 2
    val z = 0
    val sep = ","

    /*------------------------------
     | Traversable中一些有用的方法
     */

    xs.size             // 集合中元素的个数
    xs ++ ys            // 由 xs 和 ys 组合的集合
    xs map f            // 为 xs 中的每个 x 作 f(x)
    xs flatMap g        // 为 xs 中的每个 x 作 f(x)，并串联
    xs filter p         // xs 中存在 x，使得 x 满足 p(x)
    xs find p           // xs 中存在 x，使得 x 满足 p(x)，不存在则 None
    (z /: xs)(h)        // xs 中 foldLeft 从右到左对每个元素折叠 h(x,y)
    (xs :\ z)(h)        // xs 中 foldLeft 从右到左对每个元素折叠 h(x,y)，并反转
    xs.head             // 集合第一个元素(或迭代中的 next)
    xs.tail             // xs中除 xs.head 剩余的元素
    xs mkString sep     // 生成以 sep 分割的字符串



    /*------------------------------
     | JavaToTraversable
     */

    class JavaToTraversable[E](javaCollection: JCollection[E]) extends Traversable[E] {
      def foreach[U](f : E => U): Unit = {
        val iterator = javaCollection.iterator
        while(iterator.hasNext) {
          f(iterator.next)
        }
      }
    }

    val jCol = new util.ArrayList[Int]
    (1 to 5) foreach {jCol.add}

    println(jCol)

    val jtoT = new JavaToTraversable(jCol)
    println {
      jtoT map {_ * 10} filter { _ > 20}
    }
  }

  /**
   * 可变与不可变集合
   * 定义在scala.collection包中的，既是可变的、也是不可变的
   */
  test("Mutable and immutable collections"){

    println{
      (Iterable(1, 2, 3, 4, 5) dropRight 2) ++ (Iterable(1, 2, 3, 4, 5) takeRight 2)
    }
  }

  /**
   * List 和 ListBuffer
   */
  test("Working with List and ListBuffer"){

    val language = Seq("Scala","Haskell","OCaml","ML")
    println{
      language(2)
//      language(10)
    }

    val default:PartialFunction[Int,String] = {
      case _ => "Is it a functional language?"
    }
    val languageWithDefault = language orElse default

    println{
      languageWithDefault(10)
    }
    // mutable ListBuffer
    val buf = scala.collection.mutable.ListBuffer(1.2, 3.4, 5.6)
    buf(2) = 10
    println{
      buf
    }
    buf.update(2,20)
    println{
      buf
    }
  }

  /**
   * Set 和 SortedSet
   */
  test("Working with Set and SortedSet") {
    val frameworks = Set("Lift", "Akka", "Playframework", "Scalaz")
    // Both of contains and apply method doing the same things.
    assertResult(true){frameworks contains "Lift"}
    assertResult(true){frameworks("Playframework")}

    // Set包含collection.mutable.Set和collection.immutable.Set两部分
    // 其中：
    // + 和 - 为immutable.Set处理
    // += 和 -= 为mutable.Set处理

    val x = "Nico"
    val b = false
    val ms = collection.mutable.Set("Muki","Nico","Yuli","Himawali","Madoko")
    val is = collection.immutable.Set("Nao","Konata","Kagami","Taziwa","Madoko")

    /*------------------------------
    | Set中一些有用的方法
    */

    ms contains x; is(x)        // 检测 x 是否存在于 ms，等效于 ms(x)
    ms ++ is                    // 包含所有 ms，并从 is 添加元素，不添加重复的
    ms & is; ms intersect is    // ms 和 is 的交集
    ms | is; ms union is        // ms 和 is 的并集
    ms &~ is; ms diff is        // ms 和 is 的补集，等价于 (ms | is) -- is
    ms ++= is                   // 作用于mutable，从 is 添加元素，并返回ms自身
    ms(x) = b; ms.update(x,b)   // 如果b为true，则将 x 添加 xs；反之则从 xs 移除 x
    ms.clear()                  // 作用于mutable，移除ms所有元素

    // Some usage examples
    val iFrameworks = Set() + "Akka" + "Lift" + "Scalaz"
//    val iFrameworks = Set("Akka","Lift","Scalaz") - "Lift"
    val mFrameworks = collection.mutable.Set[String]()
    mFrameworks += "Akka" += "Lift"
    mFrameworks += "Scalacheck"

    // SortedSet usage exmaples
    val set1 = Set(1,2,3)
    val set2 = Set(3,4,5)
    println(set1 ++ set2)

    // SortedSet maintained the order
    val set3 = scala.collection.immutable.SortedSet(1,2,3)
    val set4 = scala.collection.immutable.SortedSet(3,4,5)

    println(set3 ++ set4)
  }

  /**
   * Map 和 Tuple
   */
  test("Working with Map and Tuple"){
//    val m = Map((1,"1st"),(2,"2nd"))
    val m = Map(1->"1st",2->"2nd")    // 键值对写法
    println(m)

    val artists = Map("Pink Floyd" -> "Rock", "Led Zeppelin" -> "Rock", "Michael Jackson" -> "Pop", "Above & Beyond" -> "Trance")
    println{
      artists filter {(t) => t._2 == "Rock"}
    }

//    val ims = collection.immutable.Map(1->"1st",2->"2nd",3->"3rd",4->"4th")
    val ms = collection.mutable.Map(1->"1st",2->"2nd",3->"3rd",4->"4th")
    val k = 9
    val v = "9th"
    val d = ""
    val kvs = Map(5->"5th",6->"6th")

    val p:Int=>Boolean = k => k > 2
    def f(v:String) = v.charAt(0)

    /*------------------------------
    | Map中一些有用的方法，其中改变数据结构等操作只适用于mutable.Map
    */
    ms getOrElse(k, d)          // 获取 ms 中键 k 的 value，没找到则返回 d
    ms + (k -> v)               // 包含 ms 所有映射和 k->v 映射的Map
    ms ++ kvs                   // 包含 ms 所有映射和 kvs 所有映射
    ms filterKeys p             // ms 中的 key 满足断言 p的映射
    ms mapValues f              // 对 ms 中的所有 value 作 f
    ms(k) = v; ms.update(k, v)  // 对 ms 中的键 k 作更新操作，k 对应的 value 被覆盖
    ms getOrElseUpdate(k, d)    // 如果 k 在 ms 中有定义，则返回对应的 value，否则添加 k->d 并返回d
    ms.clear()                  // 删除ms中的所有映射

    // for-comprehension similar to the map,filter and foreach method
    for (t <- artists; if t._2 == "Rock") yield t

  }

  /**
   * 揭开for-comprehension的神秘面纱
   */
  test("Under the hood of for-comprehension"){

    // 创建一个样本类
    case class Artist(name:String,genre:String)

    // 创建艺术家们的List
    val artists = List(
      Artist("Pink Floyd", "Rock"),
      Artist("Led Zeppelin", "Rock"),
      Artist("Michael Jackson", "Pop"),
      Artist("Above & Beyond", "trance")
    )

    // ------ map -------

    for(Artist(name,genre)<-artists; if genre == "Rock") yield name

    // In fact,the for-comprehension under hood is
    artists withFilter{
      case Artist(name,genre) => true;case _ => false
    } map {
      case Artist(name,genre) => name
    }

    // ------ foreach ------

    // For-comprehensions without yield (imperative version) are translated into a foreach
    // method call on the output of the filter.
    for(Artist(name,genre)<-artists; if genre == "Rock") println(name + ", " + genre)
    // It is same with the follow
    artists withFilter{
      case Artist(name,genre) => true;case _ => false
    } foreach {
      case Artist(name,genre) => println(name + ", " + genre)
    }

    // ------ 复杂结构 ------
    case class ArtistWithAlbums(artist: Artist, albums: List[String])

    val artistsWithAlbums = List(
      ArtistWithAlbums(Artist("Pink Floyd", "Rock"),
        List("Dark side of the moon", "Wall")),
      ArtistWithAlbums(Artist("Led Zeppelin", "Rock"),
        List("Led Zeppelin IV", "Presence")),
      ArtistWithAlbums(Artist("Michael Jackson", "Pop"),
        List("Bad", "Thriller")),
      ArtistWithAlbums(Artist("Above & Beyond", "trance"),
        List("Tri-State", "Sirens of the Sea")
      )
    )

    for {
      ArtistWithAlbums(artist, albums) <- artistsWithAlbums
      album <- albums
      if artist.genre == "Rock"
    } yield album

    // 当包含多个计数器(generator)时，Scala会使用flatMap而不是，所以上述等效于
    artistsWithAlbums flatMap {
      case ArtistWithAlbums(artist, albums) => albums withFilter {
        album => artist.genre == "Rock"
      } map { case album => album}
    }

  }

  /**
   * Option and Either
   * 在Scala中，一般不推荐使用Null，因为你需要对一个Null引用做大量的校验和检查(像类Ruby语言还好一些，因为Ruby中的Nil是单例的)
   * Option 的两个子类：Some 和 None
   * Either 的两个子类：Left 和 Right，其中Left表示失败，Right则类似于Some
   * 两者的区别在于Either用于返回具有确切意义(meaningful)的内容，Option用于有与无
   */
  test("Use Option not Null"){
    // 在Scala中，map中的get方法实现了Option功能
    val artists = Map("Pink Floyd" -> "Rock", "Led Zeppelin" -> "Rock", "Michael Jackson" -> "Pop", "Above & Beyond" -> "Trance")
    println(artists("Pink Floyd"))
    println(artists.get("Abba"))

    // Either的用法
    def throwableToLeft[T](block: => T): Either[Throwable, T] =
      try {
        Right(block)
      } catch {
        case ex:Throwable => Left(ex)
      }
    val r = throwableToLeft {
      new java.net.Socket("localhost", 4444)
    }
    r match {
      case Left(e) => e.printStackTrace()
      case Right(e) => println(e)
    }
  }

  /**
   * Working with lazy collection: views and streams
   * nonstrict collection 也被称为 lazy collection，Scala中通过view实现惰性取值
   */
  test("Convert a strict collection to a nonstrict collection with views"){

    // strict collection
    val newList = List(1, 2, 3, 4, 5).map(_ + 1)
    println(newList.head)

    def strictProcessing = List(-2, -1, 0, 1, 2) map { 2 / _ }
//    println(strictProcessing(0))        // 这里将抛出一个异常

    def nonStrictProcessing = List(-2, -1, 0, 1, 2).view map { 2 / _ }
    println(nonStrictProcessing(0))     // nonstrict collection将实现惰性求值

    // 将nonstrict collection强制转换为strict collection，则使用force方法即可
//    nonStrictProcessing.force           // 同样，这里也将抛出一个异常

    // 例子实战
    def tweets(handle: String) = {
      println("processing tweets for " + handle)
      val source = Source.fromURL(new
          java.net.URL("http://search.twitter.com/search.atom?q=" + handle))
      val iterator = source.getLines()
      val builder = new StringBuilder
      for(line <- iterator) builder.append(line)
      XML.loadString(builder.toString())
    }

    /* 和Haskell、Clean相比，Scala不是一门惰性函数式编程语言，
     * 但可以通过名传递函数(call-by-name functions)和偏函数(partial functions)实现
     */
    // 偏函数(partial function)：不指定所有参数的函数，偏函数不能留空调用，需要用占位符表示，如 tweets _
    val allTweets = Map("nraychaudhuri" -> tweets _ , "ManningBooks" -> tweets _, "bubbl_scala" -> tweets _)
    // 通过如下方式实现惰性
    allTweets.view.map{ t => t._2(t._1)}.head
    // 获取ManningBooks中的信息
    for(t <- allTweets; if t._1 == "ManningBooks") t._2(t._1)

  }

  /**
   * with head and tail of Streams structure analise
   */
  test("Working with Streams"){

    // Stream会将元素存储为两部分，head和tail，tail会在被真正需要时计算
    val num = List("zero","one","two","three","four","five").zip(Stream.from(0))

    // 以Fibonacci序列为例
    // 1. 传统做法是
    def fibonacci(n:Int):Int = n match {
      case 0 => 0
      case 1 => 1
      case i => fibonacci(i - 1) + fibonacci(i - 2)
    }
    /*
      但是实际上，上述做法有重复
      fib(8)
      fib(7) + fib(6)
      (fib(6) + fib(5)) + (fib(5) + fib(4))
      ((fib(5) + fib(4)) + (fib(4) + fib(3)) + ((fib(4) + fib(3)) + (fib(3) +
      fib(2))
      ...
     */

    // 2. 改用Stream和Tuple实现，使用Stream的con对象将(0,Steam(1,Tuple))转换，即
    // def apply[A](hd: A, tl: => Stream[A]) = new Cons(hd, tl)

    /* 说明：
     * Scala中Stream中的tail返回的是剩余的部分，如
     * val stream = (1 to 100000000).toStream
     * 则
     * stream.tail返回的是2,3,4...剩余的部分，根据模式匹配，则返回
     * scala.collection.immutable.Stream[Int] = Stream(2, ?)
     * 其中 ? 表示lazy collection没有被马上执行
     */
    val stream = (1 to 1000000000).toStream
    println(stream.tail)      // The ? symbol is the way a lazy collection shows that the end of
                              // the collection hasn’t been evaluated yet

    def fib: Stream[Int] = Stream.cons(0, Stream.cons(1, fib.zip(fib.tail).map(t => t._1 + t._2)))

    println(fibonacci(8))
    println(fib(8))
  }

  /**
   * 分而治之(divide and conquer)并行集合
   * 即分治算法处理并行集合
   */
  test("Divide and conquer with parallel collections"){

    // 带线程的并行集合
    val p = ParVector(10,20,30,40,50,60,70,80,90) map {x => println(Thread.currentThread().getName);x/2}

    // 改变原来的TaskSupport策略
    /*
       Scala中的 TaskSupport 大概有那么几个
       ForkJoinTaskSupport
       ThreadPoolTaskSupport
       ExecutionContextTaskSupport
     */
    val pv = ParVector(1,2,3)
    pv.tasksupport = new ForkJoinTaskSupport(new scala.concurrent.forkjoin.ForkJoinPool(4))     // 改为4线程的

    // FoldLeft方法不适用于并行集合，因为它的处理是按顺序执行的
    val fpv = ParVector(10, 20, 30, 40, 50, 60, 70, 80, 90).foldLeft(0) {(a,x) =>
      println(Thread.currentThread.getName); a + x }    // 它将输出单线程内容

  }

  /**
   * 并行集合层次结构
   */
  test("Parallel collection hierarchy"){

    /*
    |                           Parlterable
    |        ↓                       ↓                        ↓
    |     ParSet                  ParSeq                    ParMap
    |        │            ┌──────────┼───────────┐            │
    |        ↓            ↓          ↓           ↓            ↓
    |   ParHashSet    ParVector   ParArray    ParRage     ParHashSet
    |
     */
    // 大部分并行集合类都在scala.collection包中实现
    // 像List之类的不具有并行实现的类，虽然继承了LinearSeq，但是不使用于并行计算，不在该包中
    val sum = scala.collection.parallel.mutable.ParArray(1, 2, 3, 4).sum
    println(sum)
  }

  /**
   * 顺序集合和并行集合之间进行切换
   * 顺序集合→并行集合：par
   * 并行集合→顺序集合：seq
   */
  test("Switching between sequential and parallel collections"){

    // sequential to parallel
    val vs = Vector.range(1,10000)
    println(vs.par.filter(_ % 2 == 0))

    // parallel to sequential
    println{
      Vector.range(1,10000).par.filter(_ % 2 == 0).seq
    }
  }
}





























